/**
 * 
 */
package org.stars.daostars.core.parser;

import org.stars.dao.exception.DaoException;
import org.stars.daostars.exceptions.parser.MalformedSqlException;

import java.util.ArrayList;
import java.util.List;

/**
 * Place holder Finder.
 * 
 * @see #execute(String, ArrayList)
 * 
 * @author Francesco Benincasa (908099)
 * 
 */
abstract class PlaceHolderFinder {
	
	/**
	 * Inizio place holder
	 */
	private final static String PLACEHOLDER_START = "<[[";
	
	/**
	 * Fine place holer
	 */
	private final static String PLACEHOLDER_STOP = "]]>";
	
	/**
	 * Parentesi aperta
	 */
	private final static Character PARENTESI_APERTA = '{';

	/**
	 * Parentesi chiusa
	 */
	private final static Character PARENTESI_CHIUSA = '}';

	/**
	 * Apice
	 */
	private final static Character APICE = '\'';

	/**
	 * Data un codice sql "grezzo", sostituisce tutte le sotto query con dei
	 * place holder.
	 * <h2>Esempio</h2>
	 * Se passiamo in input una stringa:
	 * 
	 * <pre>
	 *    select * from dual { vero } { due { tre } } where 1=1
	 * </pre>
	 * 
	 * Si ottiene una query:
	 * 
	 * <pre>
	 *    select * from dual  &lt;[[0]]&gt;   &lt;[[1]]&gt;  where 1=1
	 * </pre>
	 * 
	 * E nell'array abbiamo gli elementi
	 * <ul>
	 * <li><code> vero</code> </li>
	 * <li><code> due { tre }</code></li>
	 * </ul>
	 * </p>
	 * 
	 * @param input
	 *            codice sql "grezzo"
	 * @param subQuery
	 *            array contenente tutte le sotto query.
	 * @return sql con i placeHolder.
	 * @throws DaoException
	 */
	public static String execute(String input,
			List<String> subQuery) throws MalformedSqlException {
		StringBuffer buffer = new StringBuffer();
		int counter = 0;
		int lastPos = 0;
		int pos1 = 0;
		int pos2 = 0;

		boolean errore = false;
		boolean apiceAperto = false;

		for (int idx = 0; idx < input.length() && !errore; idx++) {
			char c1 = input.charAt(idx);

			if (c1 == APICE) {
				apiceAperto = !apiceAperto;
			} else if (!apiceAperto && (c1 == PARENTESI_APERTA)) {
				if (counter == 0) {
					// memorizziamo { di livello 1
					pos1 = idx;
				}
				counter++;
			} else if (!apiceAperto && (c1 == PARENTESI_CHIUSA)) {
				counter--;

				if (counter == 0) {
					pos2 = idx;
					// siamo innanzi alla chiusura di una parentesi { } di
					// livello
					// 1. Dobbiamo togliere il pezzo di codice incluso tra
					// le graffe
					// nell'array subQuery

					if (pos1 > 0) { // mettiamo il pezzo davanti
						buffer.append(input.substring(lastPos, pos1));
					}

					lastPos = pos2 + 1;
					// al posto della subquery mettiamo @@1@@
					buffer.append(PLACEHOLDER_START + subQuery.size() + PLACEHOLDER_STOP);
					subQuery.add(input.substring(pos1 + 1, pos2));
				}
			}
		}

		if (counter != 0 || apiceAperto) {
			throw (new MalformedSqlException("Malformed sql"));
		}

		if (lastPos < input.length()) {
			buffer.append(input.substring(lastPos));
		}

		return buffer.toString();
	}
}
